import asyncio
import functools
import inspect
from typing import Union, Sequence, Optional, Callable, Any
from fastapi import Request, Response


class AuthWrapper():
    '''
    使用实力：
        @core_app.get('/w2')
        @AuthWrapper(roles=['admin', 'vip', 'novip'], permissions=['w', 'r'], fun_auth_callable=fun_auth_callable)
        async def auttlogin(re: Request):
            return '你是说'


        @core_app.get('/2AD')
        async def auttlogin(asda=Depends(AuthWrapper(roles=['admin', 'vip', 'novip'], permissions=['w', 'r'])())):
            print(asda)
            return '你是说'

    '''

    def __init__(self,
                 roles: Union[str, Sequence[str]] = None,
                 permissions: Union[str, Sequence[str]] = None,
                 fun_auth_callable: Callable = None,
                 *args, **kwargs):
        self.roles = roles
        self.permissions = permissions
        self.fun_auth_callable = fun_auth_callable
        self.args = args
        self.kwargs = kwargs

    def get_user_roles(self):
        pass

    def get_user_permissions(self):
        pass

    def __call__(self, func: Optional[Callable] = None):
        async def back_request(request: Request) -> Request:
            if self.fun_auth_callable:
                await self.fun_auth_callable(self.roles, self.permissions)
            return request

        # 返回一个协程
        if func is None:
            return back_request
        # 判断被装饰的函数
        if asyncio.iscoroutinefunction(func):
            @functools.wraps(func)
            async def async_wrapper(*args: Any, **kwargs: Any) -> Response:
                if self.fun_auth_callable:
                    if asyncio.iscoroutinefunction(self.fun_auth_callable):
                        sig = inspect.signature(func)
                        if sig:
                            await self.fun_auth_callable(self.roles, self.permissions, sig.parameters, args, kwargs)
                        else:
                            await self.fun_auth_callable(self.roles, self.permissions, args, kwargs)
                    else:
                        raise Exception("fun_auth_callable ness used in 'await' ")
                try:
                    # 查当前被装饰的函数有哪些参数值信息  # 查验当前函数有哪些参数值得传入
                    return await func(*args, **kwargs)
                finally:
                    pass

            return async_wrapper
        else:
            @functools.wraps(func)
            def sync_wrapper(*args: Any, **kwargs: Any) -> Response:

                # print("ssssssssssssssssssssssss",sig)
                # for idx, parameter in enumerate(sig.parameters.values()):
                #     print("参数信息",idx, parameter, parameter.name)
                if self.fun_auth_callable:
                    sig = inspect.signature(func)
                    if sig:
                        self.fun_auth_callable(self.roles, self.permissions, sig.parameters, args, kwargs)
                    else:
                        self.fun_auth_callable(self.roles, self.permissions, args, kwargs)
                return func(*args, **kwargs)

            return sync_wrapper
